#include "SubsystemBedWarsTerrain.h"
#include "TerrainContentsGeneratorBedWars.h"
#include "ServerConfigure.h"
// #include "TerrainSerializerBedWars.h"
#include "GameSingleton.h"
#include "Managers/GameManager.h"
#include "BedWars.h"
#include "Log.h"
// #include "Terrain/TerrainUpdater.h"
#include "TerrainUpdaterBedWars.h"
#include "GameThreadPool.hpp"

using namespace PocketSurvival;

namespace BedWars
{
    SubsystemBedWarsTerrain::SubsystemBedWarsTerrain(){}


    void SubsystemBedWarsTerrain::discardTerrainModify(std::vector<Point2> &discardChunkVec)
    {
        m_chunkMapLock.lock();

        std::map<Point2, TerrainChunk*> chunkMapCatch;

        for(auto &pair : m_chunkMap)
        {
            if(pair.second->isChange == true)
            {
                // 放入缓存队列，重复利用

                discardChunkVec.push_back(pair.first);
                if(m_chunkQueue.enqueue(pair.second) == false)
                {
                    Log::Error("[bedwars]回收TerrainChunk失败");
                }
                // pair.second->isRemove = true;
            }
            else
            {
                // if(m_chunkQueue.enqueue(pair.second) == false)
                // {
                //     Log::error("[bedwars]回收TerrainChunk失败");
                // }
                // chunkMapCatch[pair.first] = pair.second;
                chunkMapCatch.emplace(pair.first, pair.second);
            }
        }

        m_chunkMap.swap(chunkMapCatch);
        // m_chunkMap.clear();
        // std::swap(m_chunkMap, chunkMapCatch);

        m_chunkMapLock.unlock();
    }

    void SubsystemBedWarsTerrain::update(float dt)
    {   
        // ========================== 回收区块 ===========================
        std::vector<Point2> removeChunkVec;
        m_chunkMapLock.lock();
        for(auto it = m_chunkMap.cbegin(); it != m_chunkMap.cend(); ++it)
        {
            if(it->second->isRemove == true)
            {
                removeChunkVec.push_back(it->first);
            }
        }
        m_chunkMapLock.unlock();

        for (const Point2& removeChunkPoint : removeChunkVec)
        {
            TerrainChunk *terrainChunk = nullptr;
            m_chunkMapLock.lock();
            auto findIt = m_chunkMap.find(removeChunkPoint);
            if (findIt != m_chunkMap.end())
            {
                terrainChunk = findIt->second;
                m_chunkMap.erase(findIt);
            }
            m_chunkMapLock.unlock();

            if (terrainChunk != nullptr)
            {
                // 通知所有子系统，有区块将要被回收处理
                for (auto &pair : GameSingleton::gameManager->subsystemMap)
                {
                    pair.second->onTerrainChunkRemoved(terrainChunk);
                }

                // 区块有改变的话，则需要保存处理
                if (terrainChunk->isChange == true && bedWaresCore->isEditMode == true)
                {
                    // 这里用到保存线程池
                    GameSingleton::gameSaveThreadPool->push_task([terrainChunk,this]
                    {
                        terrainSerializer->saveChunk(terrainChunk);
                        m_chunkQueue.enqueue(terrainChunk);
                    });
                }
                else
                {
                    m_chunkQueue.enqueue(terrainChunk);
                }
            }
            else
            {
                Log::Error("地形回收错误!!");
            }
        }
        // =================================================================

        TerrainChunk *loadTerrainChunk;
        while(m_loadFinishChunkQueue.try_dequeue(loadTerrainChunk))
        {
            m_chunkMapLock.lock();
            if (m_chunkMap.find(loadTerrainChunk->coords) == m_chunkMap.end())
            {
                m_chunkMap[loadTerrainChunk->coords] = loadTerrainChunk;
            }
            else
            {
                m_chunkMapLock.unlock();
                continue;
            }
            m_chunkMapLock.unlock();

            for (auto &pair : GameSingleton::gameManager->subsystemMap)
            {
                pair.second->onTerrainChunkAdded(loadTerrainChunk);
            }
        }
        

        // 只有将需要回收的区块回收处理完后才能调用地形刷新和后面的地形生成
        terrainUpdater->update(dt);

        // processModifiedCells();
        GameSingleton::gameThreadPool->push_task(&SubsystemTerrain::processModifiedCells, this);

        Point2 point;
        while(m_waitLoadChunkQueue.try_dequeue(point))
        {
            m_chunkMapLock.lock();
            if(m_chunkMap.find(point) != m_chunkMap.end())
            {
                m_chunkMapLock.unlock();
                continue;
            }
            m_chunkMapLock.unlock();
            GameSingleton::gameNoWaitThreadPool->push_task([point, this]
            {
                loadChunk(point);
            });
        }
    }

    void SubsystemBedWarsTerrain::load(const nlohmann::json &json)
    {
        SubsystemTerrain::load(json);
        GameSingleton::serverConfigure->terrainChunkRecycleTime = 10.0f;
        terrainContentsGenerator = std::make_shared<TerrainContentsGeneratorBedWars>();
        terrainUpdater = std::make_shared<TerrainUpdaterBedWars>();
    }

    void SubsystemBedWarsTerrain::save(nlohmann::json &json)
    {
        if(bedWaresCore->isEditMode == true)
        {
            saveAllChunk();
            terrainSerializer->saveAllRegion();
        }
    }

}